#include "SNumber.h"
#include <iomanip>

SNumberSp SNumber::Parse(string s)
{
	trim(s);

	// Check the syntax:
	//  - from 1 to 10 digits ( 0, 10, 100, 999, 1234567890 )
	//  - a "0x" followed by 1 to 8 exadecimal digit ( 0x0, 0xA, 0xab, 0xF6, 0xFED2A2B0 )

	regex reg_dec("[+]?\\d{1,10}");        // Decimal value
	regex reg_hex("0x[0-9a-fA-F]{1,8}");   // Hexadecimal value
	bool syntax_error = false;
	unsigned long n = 0;
	
	if ( regex_match(s, reg_dec) )
	{
		// Decimal conversion				
		try
		{
			n = lexical_cast<unsigned long>( s );
		}
		catch(bad_lexical_cast&)
		{
			syntax_error = true;
		}
	}
	else if ( regex_match(s, reg_hex) )
	{			
		// Hexadecimal conversion
		n = Utility::HexToDec( s.substr(2) );
	}
	else
	{
		syntax_error = true;
	}
	
	if ( syntax_error )
	{
		throw SParseException("Syntax error: " + s + " is not a SNumber literal.");
	}

	return SNumber::Create( n );
}

std::string SNumber::ToString( string format )
{
	ostringstream os;
	
	if ( format.empty() || format == "d")
	{
		os << value;
	}
	else if ( format == "x")
	{
		os << "0x" << uppercase << hex << value;
	}
	else if ( format == "nx")
	{
		os << uppercase << hex << value;
	}

	smatch m;

	// format: <num>x
	if ( regex_search(format, m, regex("(\\d+)x") ) )
	{
		int n;

		try
		{
			n = lexical_cast<int>( m[1] );
		}
		catch(bad_lexical_cast&)
		{
			n = 1;
		}

		os << "0x" << setfill('0') << setw(n) << uppercase << hex << value;
	}

	// format: <num>nx
	if ( regex_search(format, m, regex("(\\d+)nx") ) )
	{
		int n;

		try
		{
			n = lexical_cast<int>( m[1] );
		}
		catch(bad_lexical_cast&)
		{
			n = 1;
		}

		os << setfill('0') << setw(n) << uppercase << hex << value;
	}

	return os.str();
}

SNumberSp SNumber::Create( unsigned long value )
{
	return SNumberSp(new SNumber(value));
}